﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;

namespace DGen
{
    /// <summary>
    /// DataType helper class. 
    /// </summary>
    public static class DTypes
    {
        /// <summary>
        /// is this object numeric? Returns true or false.
        /// </summary>
        /// <param name="ObjectToTest"></param>
        /// <returns></returns>
        public static bool IsNumeric(object ObjectToTest)
        {
            // from : http://www.tangiblesoftwaresolutions.com/Articles/CSharp%20Equivalent%20to%20IsNumeric.htm
            if (ObjectToTest == null)
            {
                return false;
            }
            else
            {
                double OutValue;
                return double.TryParse(ObjectToTest.ToString().Trim(),
                                       NumberStyles.Any,
                                       CultureInfo.CurrentCulture,
                                       out OutValue);
            }
        }
        /// <summary>
        /// is this number an integer?
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        public static bool IsInteger(double d)
        {
            bool IsIntegerValue = false;


            Double remainder = Math.IEEERemainder(d, 1);
            if (remainder == 0)
            {
                IsIntegerValue = true;
            }
            else
            {
                IsIntegerValue = false;
            }
            return IsIntegerValue;
        }
        /// <summary>
        /// is this string an percentage
        /// </summary>
        /// <param name="theValue"></param>
        /// <returns></returns>
        public static bool IsStringPercentage(string theValue)
        {
            if (theValue.Contains("%"))
            {
                if (IsNumeric(theValue.Replace("%", String.Empty)))
                {
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// Can this string be converted to decimal? 
        /// Relies on exception raising, so do not overuse.
        /// </summary>
        /// <param name="theValue"></param>
        /// <returns></returns>
        public static bool IsStringDecimal(string theValue)
        {
            for (int i = 0; i < theValue.Length; i++)
            {
                if (Char.IsLetter(theValue[i]) == true)
                {
                    return false;
                }
            }
            try
            {
                Convert.ToDecimal(theValue);
                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// Does this string convert to integer? Uses exception so watch performance.
        /// </summary>
        /// <param name="theValue"></param>
        /// <returns></returns>
        public static bool IsStringInteger(string theValue)
        {
            try
            {
               
                Convert.ToInt32(theValue);
                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// Matches to see if fits any YYYY-MM-DD or DD-MM-YYYY.
        /// Allows for YYYY.MM.DD or DD/MM/YYYY or any reasonable combination.
        /// Does not check for nonsensical dates (e.g. 29th February 2003)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static bool IsDate(string input)
        {
            bool rtnAnswer = false;
            //    input = input.Trim();
            input = input.Replace('/', '-');
            input = input.Replace('.', '-');

            string SQLDateTime = @"(\d+)-(\d+)-(\d+)(\d+):(\d+):(\d+)-(\d+)";
            // DD-MM-YYYY dates
            string DDMMYYYY =
                @"^([3][0-1]|[2][0-9]|[1][0-9]|[0][1-9])-([1][0-2]|[0][1-9]|[1-9])-([1][0-9]{3}|[2][0-9]{3})$";
            // MM-DD-YYYY dates
            string MMDDYYYY =
                @"^([1][0-2]|[0][1-9]|[1-9])-([3][0-1]|[2][0-9]|[1][0-9]|[0][1-9])-([1][0-9]{3}|[2][0-9]{3})$";
            // YYYY-MM-DD dates
            string YYYYMMDD =
                @"^([1][0-9]{3}|[2][0-9]{3})-([1][0-2]|[0][1-9]|[1-9])-([3][0-1]|[2][0-9]|[1][0-9]|[0][1-9])$";
            // YYYY-DD-MM dates
            string YYYYDDMM =
                @"^([1][0-9]{3}|[2][0-9]{3})-([3][0-1]|[2][0-9]|[1][0-9]|[0][1-9])-([1][0-2]|[0][1-9]|[1-9])$";


            rtnAnswer = isMatch(input, SQLDateTime);
            if (rtnAnswer == false)
            {
                rtnAnswer = isMatch(input, DDMMYYYY);
            }
            if (rtnAnswer == false)
            {
                rtnAnswer = isMatch(input, MMDDYYYY);
            }
            if (rtnAnswer == false)
            {
                rtnAnswer = isMatch(input, YYYYMMDD);
            }
            if (rtnAnswer == false)
            {
                rtnAnswer = isMatch(input, YYYYDDMM);
            }


            return rtnAnswer;
        }
        private static bool isMatch(string input, string p5)
        {
            Match m5 = Regex.Match(input, p5);
            if (m5.Success)
            {
                Console.WriteLine(m5);
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Returns the probable datatype of a given string value.
        /// </summary>
        /// <param name="colValue"></param>
        /// <returns></returns>
        public static DataTypes GuessMyType(string colValue)
        {
            DataTypes returnType = DataTypes.unknown;


            if (IsNumeric(colValue))
            {
                if (colValue.StartsWith("0") && !colValue.Contains(".") && colValue.Trim().Replace("0", String.Empty).Length > 0)
                {
                    /* This may seem like an odd choice, but this is to catch character strings which start with 0.
                     * this is a big issue for the environment I work in where our property references (unique identifiers) are often of 
                     * the form 099032100 and where the leading zero matters. So anything which starts with a zero, without a decimal
                     * point and which is not 0 or 00 or 000 or 0000 (etc) is classed as a varchar.
                     *                  - Darian Linehan
                     *                  22/07/2009 21:57:46
                     */
                    returnType = DataTypes.varchar;
                }
                else if (!colValue.Trim().StartsWith("-") && colValue.Contains("-"))
                {
                    returnType = DataTypes.varchar;
                }
                else if (colValue.Trim().StartsWith("-") && colValue.Replace("-", String.Empty).Length + 1 < colValue.Length)
                {
                    //returnType = DataTypes.varchar;
                }
                if (returnType == DataTypes.unknown)
                {
                    colValue = DText.CleanNumeric(colValue, true);
                    double d = 0.0;
                    if (colValue.EndsWith("-"))
                    {
                        colValue = colValue.Replace("-", String.Empty);
                    }
                    if (colValue.ToLower().Contains("e"))
                    {
                        NumberFormatInfo info = new NumberFormatInfo();
                        info.NumberDecimalSeparator = ".";
                        d = Double.Parse(colValue, NumberStyles.Float, info);
                    }
                    else
                    {
                        d = Convert.ToDouble(colValue);
                    }


                    if (IsInteger(d) && !colValue.Contains("."))
                    {
                        if (d > 2147483000 || d < -2147483000)
                        {
                            returnType = DataTypes.bigint;
                        }
                        else
                        {
                            returnType = DataTypes.integer;
                        }
                    }
                    else
                    {
                        returnType = DataTypes.numeric;
                    }
                }
            } // END OF NUMERIC BIT;
            else
            {
                returnType = DataTypes.varchar;
            }
            if (IsDate(colValue))
            {
                returnType = DataTypes.datetime;
            }
            if (IsStringPercentage(colValue))
            {
                returnType = DataTypes.percentage;
            }
            return returnType;
        }
        /// <summary>
        /// PRECEDENCE OF DataTypes
        /// </summary>
        /// <param name="old1"></param>
        /// <param name="new1"></param>
        /// <returns></returns>
        public static DataTypes chooseDataType(DataTypes old1, DataTypes new1)
        {
            DataTypes WinningDataType = DataTypes.unknown;

            if (old1 > new1)
            {
                WinningDataType = old1;
            }
            else
            {
                WinningDataType = new1;
            }
            return WinningDataType;
        }
    }
}
